import path from 'path';

import { Storage } from '$infra';
import { ChokidarFileWatcher, logger, WatcherEvent } from '$common';

function getRelativePosixPath(filePath: string, baseDir: string): string {
  const relativePath = path.relative(baseDir, filePath);
  return path.posix.normalize(relativePath);
}

export class SimulationWatcher {

  private _watchDir: string;
  private _mountPath: string;
  private _watcher: ChokidarFileWatcher;

  constructor(watchDir?: string, mountPath?: string) {
    this._watchDir = watchDir;
    this._mountPath = mountPath;
  }

  public setWatchDirectory(watchDir: string) {
    this._watchDir = watchDir;
  }

  public setMountPath(mountPath: string) {
    this._mountPath = mountPath;
  }

  private _upload = async (filePath: string) => {
    const objectName = `${this._mountPath}/${getRelativePosixPath(filePath, this._watchDir)}`;
    await Storage.Instance.fPutObject(objectName, filePath);
  }

  private _delete = async (filePath: string) => {
    const objectName = `${this._mountPath}/${getRelativePosixPath(filePath, this._watchDir)}`;
    if (await Storage.Instance.checkObjectNameExist(objectName)) {
      await Storage.Instance.deleteObject(objectName);
    }
  }

  public start() {
    if (!this._watcher) {
      logger.debug(`👀 Listen for changes(add, modify, delete) of files in directory ${this._watchDir}`);
      this._watcher = new ChokidarFileWatcher(this._watchDir);
      this._watcher.on(WatcherEvent.FileAdded, this._upload);
      this._watcher.on(WatcherEvent.FileChanged, this._upload);
      this._watcher.on(WatcherEvent.FileRemoved, this._delete);
      this._watcher.start();
    }
  }

  public stop() {
    if (this._watcher) {
      this._watcher.stop();
    }
  }
}